/* 
    Copyright (c) 2012 - 2013 Microsoft Corporation.  All rights reserved.
    Use of this sample source code is subject to the terms of the Microsoft license 
    agreement under which you licensed this sample source code and is provided AS-IS.
    If you did not accept the terms of the license agreement, you are not authorized 
    to use this sample source code.  For the terms of the license, please see the 
    license agreement between you and Microsoft.
  
    To see all Code Samples for Windows Phone, visit http://code.msdn.microsoft.com/wpapps
  
*/
using Microsoft.Phone.Controls;
using Microsoft.Xna.Framework.Media;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace TakePhotoTogether
{
    class LensViewModel : DependencyObject, INotifyPropertyChanged, IDisposable
    {
        // Our convention is that we will store the thumbnail of a file named foo.jpg as
        // foo.jpg.thumb.jpg
        //
        private const string thumbnailSuffix = ".thumb.jpg";
        private const string photosDirectoryName = "Photos";

        #region Private fields

        private MediaLibrary mediaLibrary = new MediaLibrary();

        #endregion

        #region Public events

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Public properties

        public static readonly DependencyProperty CameraRollProperty = DependencyProperty.Register(
            "CameraRoll",
            typeof(ObservableCollection<object>),
            typeof(LensViewModel),
            new PropertyMetadata(new ObservableCollection<object>(), onCameraRollChanged));

        public ObservableCollection<object> CameraRoll
        {
            get { return (ObservableCollection<object>)GetValue(CameraRollProperty); }
            set { SetValue(CameraRollProperty, value); }
        }


        public static readonly DependencyProperty PreviewBrushProperty = DependencyProperty.Register(
            "PreviewBrush",
            typeof(VideoBrush),
            typeof(LensViewModel),
            null);

        public VideoBrush PreviewBrush
        {
            get { return (VideoBrush)GetValue(PreviewBrushProperty); }
            set { SetValue(PreviewBrushProperty, value); }
        }

        public static readonly DependencyProperty ViewfinderRotationProperty = DependencyProperty.Register(
            "ViewfinderRotation",
            typeof(double),
            typeof(LensViewModel), 
            new PropertyMetadata(90.0));

        public double ViewfinderRotation
        {
            get { return (double)GetValue(ViewfinderRotationProperty); }
            set { SetValue(ViewfinderRotationProperty, value); }
        }

        public static readonly DependencyProperty ReviewImageBitmapProperty = DependencyProperty.Register(
            "ReviewImageBitmap",
            typeof(WriteableBitmap),
            typeof(LensViewModel),
            null);

        public WriteableBitmap ReviewImageBitmap
        {
            get { return (WriteableBitmap)GetValue(ReviewImageBitmapProperty); }
            set { SetValue(ReviewImageBitmapProperty, value); }
        }



        public bool CameraRollIsNotEmpty
        {
            get
            {
                if (this.CameraRoll == null)
                {
                    return false;
                }
                return this.CameraRoll.Count > 0;
            }
        }

        public Visibility PlaceHolderVisibility { get; set; }

        #endregion

        public LensViewModel()
        {
            createPhotosFolder();
        }

        #region Public Methods

        public void LoadCameraRoll()
        {
            PlaceHolderVisibility = Visibility.Visible;
            List<IThumbnailedImage> tempCameraRoll = new List<IThumbnailedImage>();

            // Lenses don't typically display the entire camera roll, only photos captured during the 
            // current session.  Uncomment the following line to display the entire camera roll anyway.
            //
            loadFromMediaLibrary(tempCameraRoll);

            loadFromIsolatedStorage(tempCameraRoll);

            tempCameraRoll.Sort(new ThumbnailedImageDateComparer());

            this.CameraRoll = new ObservableCollection<object>(tempCameraRoll);


            if (tempCameraRoll.Count > 0)
            {
                PlaceHolderVisibility = Visibility.Collapsed;
                onPropertyChanged("PlaceHolderVisibility");
            }
        }

        public void DeletePhoto(int index)
        {
            LocalFolderThumbnailedImage image = this.CameraRoll[index] as LocalFolderThumbnailedImage;
            if (image == null)
            {
                throw new ArgumentException();
            }

            string fileName = image.ImageFileName;
            string thumbName = image.ThumbnailFileName;
            image = null;

            this.CameraRoll.RemoveAt((int)index);

            using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
            {
                storage.DeleteFile(fileName);
                storage.DeleteFile(thumbName);
            }
        }

        public MediaLibraryThumbnailedImage PathImageMediaLibrary(int index)
        {
            MediaLibraryThumbnailedImage image = this.CameraRoll[index] as MediaLibraryThumbnailedImage;
            if (image == null)
            {
                throw new ArgumentException();
            }

            return image;
        }

        #endregion

        #region Private Helper Methods

        private void loadFromMediaLibrary(List<IThumbnailedImage> tempCameraRoll)
        {
            PictureAlbum rootAblum = this.mediaLibrary.RootPictureAlbum;

            foreach (PictureAlbum album in rootAblum.Albums)
            {
                if (album.Name == "Camera Roll")
                {
                    foreach (Picture picture in album.Pictures)
                    {
                        tempCameraRoll.Add(new MediaLibraryThumbnailedImage(picture));
                    }
                }
            }
        }

        private void loadFromIsolatedStorage(List<IThumbnailedImage> tempCameraRoll)
        {
            using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                string[] photoFileNames = store.GetFileNames(Path.Combine(photosDirectoryName, "*.*"));
                foreach (string photoFileName in photoFileNames)
                {
                    if (photoFileName.Contains(thumbnailSuffix) == false)
                    {
                        string thumbnailFileName = photoFileName + thumbnailSuffix;
                        string photoFileNameAndPath = Path.Combine(photosDirectoryName, photoFileName);
                        string thumbnailFileNameAndPath = Path.Combine(photosDirectoryName, thumbnailFileName);

                        // Make sure it has a thumbnail file before adding it
                        //
                        if (store.FileExists(thumbnailFileNameAndPath) == true)
                        {
                            tempCameraRoll.Add(new LocalFolderThumbnailedImage(photoFileNameAndPath, thumbnailFileNameAndPath));
                        }
                    }
                }
            }
        }

        private void createPhotosFolder()
        {
            using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!store.DirectoryExists(photosDirectoryName))
                    store.CreateDirectory(photosDirectoryName);
            }
        }

        private void copySampleFilesToIsolatedStorage()
        {
            // Visual Studio deploys our sample photos to the installation directory of the app.
            // To better simulate real world usage of photos in isolated storage (e.g. you'll 
            // definitely need write access to the location they are stored in, and you don't have
            // write access to the installation folder), we'll copy them to isolated storage if we
            // haven't already.
            //

            using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (store.GetDirectoryNames().Contains<string>(photosDirectoryName))
                {
                    // They have already been copied, don't do anything
                    //
                    return;
                }

                store.CreateDirectory(photosDirectoryName);

                string[] photoFileNames = { "Photos\\PlaceHolder.png", "Photos\\PlaceHolder.png.thumb.jpg" };

                foreach(string photoFileName in photoFileNames)
                {
                    using (Stream input = Application.GetResourceStream(new Uri(photoFileName, UriKind.Relative)).Stream)
                    {
                        using (IsolatedStorageFileStream output = store.CreateFile(photoFileName))
                        {
                            byte[] readBuffer = new byte[4096];
                            int bytesRead = -1;

                            // Copy the file from the installation folder to isolated storage. 
                            while ((bytesRead = input.Read(readBuffer, 0, readBuffer.Length)) > 0)
                            {
                                output.Write(readBuffer, 0, bytesRead);
                            }
                        }
                    }
                }
            }
        }

        private void onPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private string generatePhotoName()
        {
            return DateTime.Now.ToString("yyyy.MM.dd.HH.mm.ss") + ".LensSample";
        }


        private static void onCameraRollChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            LensViewModel viewModel = (LensViewModel)sender;

            if (e.OldValue != null)
            {
                ((ObservableCollection<object>)e.OldValue).CollectionChanged -= viewModel.lensViewModel_CollectionChanged;
            }
            if (e.NewValue != null)
            {
                ((ObservableCollection<object>)e.NewValue).CollectionChanged += viewModel.lensViewModel_CollectionChanged;
            }

            viewModel.onPropertyChanged("CameraRollIsNotEmpty");
        }

        private void lensViewModel_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            onPropertyChanged("CameraRollIsNotEmpty");
        }

        #endregion

        public void Dispose()
        {
            var cameraRoll = CameraRoll;
            if (cameraRoll != null)
            {
                foreach (IThumbnailedImage image in cameraRoll)
                {
                    if (image != null)
                        image.Dispose();
                }
                cameraRoll.Clear();
            }
            CameraRoll = null;
            mediaLibrary = null;
            GC.SuppressFinalize(this);
        }
    }
}
